'use strict'

const bencode = require('bencode');
const crypto = require('crypto');
const dgram = require('dgram');

//配置文件
const config = require('./config');
//工具
const tools = require('./tools');
//数据库
const db = require('./db');

class index {
    constructor(port, address){
        this.port = port;
        this.address = address;
        //生成随机nid
        this.id = tools.randomId();
        //创建空路由表
        this.nodesList = [];

        //创建UDP连接对象
        this.socket = dgram.createSocket('udp4');
        //绑定错误处理
        this.socket.on('error',function (err) {
            console.error(`socket error:\n${err.stack}`);
            this.socket.close();
        });

        //绑定message处理
        this.socket.on('message',(packet, rinfo) => this.onMessage(packet, rinfo));


        //绑定端口和主机
        if (this.address){
            this.socket.bind(this.port,this.address);
        }else {
            this.socket.bind(this.port);
        }
    }

    start(){
        console.log('start....');
        process.on('exit',function (code) {
            console.log(`dht process is exited...exit code: ${code}`);
        });
        db.connectDB();
        if (this.nodesList.length !== 0){
            //已经有节点
            // console.log('已经有节点');
            this.findNodesList();
        }else{
            //没有节点 加入dht网络
            this.joinDht();
            setInterval(() =>{
                if (this.nodesList.length === 0){
                 return this.joinDht();
                }
                this.findNodesList();
            },config.cycleTimes);
        }
    }

    joinDht(){
        // console.log('加入dht网络');
        const superNodes = config.superNodes;
        superNodes.forEach((v) => this.findNode(v));
    }

    findNodesList(){
        // console.log('findNodesList');
        this.nodesList.forEach((node) => this.findNode(node, node.nid));
        this.nodesList = [];
    }

    //向节点发送请求
    findNode(target, nid){
        // console.log('findNode -->',target,'   nid --->',nid);
        const id = nid != undefined ? tools.genNeighborId(nid,this.id) : this.id;
        const  msg = {
            t: crypto.randomBytes(2),
            y:'q',
            q:'find_node',
            a:{
                id,
                target:tools.randomId()
            }
        }
        this.request(msg,target);
    };

    //发送UDP请求
    request(msg,target){
        const address = target.address;
        const port = target.port;
        const packet = bencode.encode(msg);
        const len = packet.length;
        this.socket.send(packet,0,len,port,address);
    }

    //响应
    response(r, t, rinfo) {
        const packet = bencode.encode({
            t,
            r,
            y: 'r'
        });
        const len = packet.length;
        const address = rinfo.address;
        const port = rinfo.port;
        if (port < 1 || port > 65535) {
            console.log('port is invalid');
            return ;
        }

        this.socket.send(packet, 0, len, port, address);
    }

    //处理消息
    onMessage(packet, rinfo){
        try{
            var msg = bencode.decode(packet);
        }catch (e){
            console.error('decode error');
            return;
        }

        if (msg.y){
            var y = msg.y.toString();
        }
        //过滤不符合协议的查询
        if (!msg.t){
            return console.log('t is required!');
        }

        if (!y || y.length !== 1){
            return console.log('y is required!');
        }

        if (y === 'e'){
            return console.log('can not process e!');
        }

        if (y === 'q'){
            if (!msg.a) {
                return console.log('a is required!');
            }

            if (!msg.a.id || msg.a.id.length !== 20) {
                return console.log('id is required!');
            }

            if (msg.q) {
                var q = msg.q.toString();
            } else {
                return ;
            }
            //处理不同类型的查询
            switch (q) {
                case 'ping':
                    this.toPing(msg, rinfo);
                    break;
                case 'find_node':
                    this.toFindNode(msg, rinfo);
                    break;
                case 'get_peers':
                    this.toGetPeers(msg, rinfo);
                    break;
                case 'annouce_peer':
                    this.toAnnouncePeer(msg, rinfo);
                    break;
                default:
                    console.log('q is unknown');
            }
        }

        if (y === 'r') {
            if (msg.r.nodes) {
                var nodes = tools.decodeNodes(msg.r.nodes);
            } else {
                return ;
            }

            const len = nodes.length;
            if (len !== 0) {
                for (let i = 0; i < len; i++) {
                    //将node加入路由表
                    let node = nodes[i];
                    if (node.port < 1 || node.port > 65535) {
                        console.log('port is invalid');
                        continue;
                    }
                    this.nodesList.push({
                        nid: node.nid,
                        address: node.address,
                        port: node.port
                    });
                }
            }

        }
    }

    //响应ping查询
    toPing(msg,rinfo){
        const r = {
            id: this.id
        };
        this.response(r, msg.t, rinfo);
    }

    //响应ping查询
    toFindNode(msg,rinfo){
        const r = {
            id: this.id,
            nodes:''
        };
        this.response(r, msg.t, rinfo);
    }

    //响应getPeer查询
    toGetPeers(msg, rinfo) {
        if (msg.a && msg.a.info_hash && msg.a.info_hash.length === 20) {
            var infohash = msg.a.info_hash;
            console.log(infohash.toString('hex'));
            // model.saveInfoHash(infohash.toString('hex'));
            db.addInfoHash(infohash.toString('hex'));
        } else {
            return ;
        }

        const r = {
            id: tools.genNeighborId(infohash, this.id),
            token: crypto.randomBytes(4),
            nodes: ''
        };
        this.response(r, msg.t, rinfo);
    }

    //响应annoucePeer查询
    toAnnouncePeer(msg, rinfo) {
        if (msg.a && msg.a.info_hash && msg.a.info_hash.length === 20) {
            console.log(msg.a.info_hash.toString('hex'));
            db.addInfoHash(msg.a.info_hash.toString('hex'));
            // model.saveInfoHash(msg.a.info_hash.toString('hex'));
        } else {
            return ;
        }

        const r = {
            id: this.id
        };

        this.response(r, msg.t, rinfo);
    }
}

module.exports = index;